﻿/// <reference path="_namespace.js" />
/// <reference path="../drawing/Colour.js"/>
/// <reference path="../components/Component.js" />
/// <reference path="../windows/WinForm.js" />
/// <reference path="../effects/Animation.js" />
/// <reference path="../drawing/DeviceTypes.js" />
/// <reference path="../geometry/shapes/Rectangle.js" />

/*****************************************************************************
Ajax library class definition. Kevin Robinson 2008.
Class: ajax.xna.Game
/*****************************************************************************/

ajax.lang.addNamespace("ajax.xna");
ajax.lang.imports("ajax.drawing.Device3D");
ajax.lang.imports("ajax.effects.Animation");
ajax.lang.imports("ajax.drawing.Colour");
ajax.lang.imports("ajax.drawing.DeviceTypes");

//-----------------------------------------------------------------------------
ajax.xna.Game = function(doc, sLayerName, w, h, displayFlags, sText, parentNode, bModal, taskBar)
{///<field name="graphicsDevice" type="ajax.drawing.Device3D"/>
    ajax.xna.Game.superConstructor.call(this, doc, sLayerName, w, h, displayFlags, sText, parentNode, bModal, taskBar);
    
    // Use xna icon
    this.iconFile           = ajax.getDomainPath() + "/images/xna.gif";
    this.contentStyle.overflow = "hidden";
    
    // 16.66 = Aim for 60FPS - you're not gonna get it but you can dream?
    this.loop = new ajax.effects.Animation(this.doc, 0, 0);
    this.loop.callback = this.loopController.bind(this);
    
    this.backColour = ajax.drawing.Colour.cornflowerBlue();
}

$extend("ajax.xna.Game", "ajax.windows.WinForm");
if ($getDesignMode())
    ajax.xna.Game.prototype = ajax.windows.WinForm.prototype;    
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Statics first
ajax.xna.Game.cast = function(obj)
{///<returns type="ajax.xna.Game"/>
    return obj;                   
}

//-----------------------------------------------------------------------------
// Public virtual Members
ajax.xna.Game.prototype.graphicsDevice  = null; if ($getDesignMode()) ajax.xna.Game.prototype.graphicsDevice = ajax.drawing.Device3D.prototype;
ajax.xna.Game.prototype.components      = [];
ajax.xna.Game.prototype.gameServices    = {}; // loosely typed collection for extra globals?
ajax.xna.Game.prototype.loop            = ajax.effects.Animation.prototype; 
ajax.xna.Game.prototype.backColour      = ajax.drawing.Colour.prototype;
ajax.xna.Game.prototype.targetFrameRate = 0;
ajax.xna.Game.prototype.loopMilliseconds= 0;

//-----------------------------------------------------------------------------
// Public virtual Methods
ajax.xna.Game.prototype.setBackColour   = function(value)
{
    // Set backcolour
    this.backColour = value;
    this.getContent().style.backgroundColor = this.backColour.toHex();
}

//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.initializeComponents = function()
{    
    for (var i = 0; i < this.components.length; i++)
        this.components[i].initialize();
}

//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.updateComponents = function(gameTime)
{///    
    // Call Update on all game components
    for (var i = 0; i < this.components.length; i++)
        this.components[i].update(gameTime); 
}

//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.drawComponents = function(gameTime)
{    
    // Call Draw on all DrawableGameComponents  
    for (var i = 0; i < this.components.length; i++)
        if (this.components[i].draw && this.components[i].getVisible())
            this.components[i].draw(gameTime); 
}

//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.update = function(gameTime)
{///<summary>Empty stub method (no need to call base). Update your states here per frame.</summary>      
 ///<param name="gameTime" type="ajax.drawing.Timer"/>       
}
//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.beginDraw = function()
{
    this.graphicsDevice.beginScene();
}

//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.draw = function(gameTime)
{///<summary>Empty stub method (no need to call base). Do your drawing here per frame.</summary>      
 ///<param name="gameTime" type="ajax.drawing.Timer"/>         
   
    gameTime = ajax.drawing.Timer.cast(gameTime);   
    
    this.graphicsDevice.clear(this.backColour);
    
    this.setText("Ajaxna (Default Rendering Test - pls override draw method.)");    
    var moveSpeed = gameTime.elapsedTime * 0.1;    
    
    // Draw logo image
    if (!this.demoLogoImage)
    {
        this.demoLogoImage = this.getDocument().createElement("img");
        this.demoLogoImage.src = ajax.domain + "/images/logo.gif";             
        this.demoLogoRect = new ajax.geometry.shapes.Rectangle(0, 0, 457, 78);
        this.demoLogoVelocity = new ajax.math.Vector3(2, 2, 0);              
    }
    
    
    this.graphicsDevice.graphics.drawImageToRect(this.demoLogoImage, this.demoLogoRect);

    
    if (this.demoLogoRect.x < 0 || this.demoLogoRect.x + this.demoLogoRect.width > this.getContentRect().width)     
        this.demoLogoVelocity.x *= -1;
    
    if (this.demoLogoRect.y < 0 || this.demoLogoRect.y + this.demoLogoRect.height > this.getContentRect().height)
        this.demoLogoVelocity.y *= -1;           
    
    
    
    this.demoLogoRect.x += this.demoLogoVelocity.x;
    this.demoLogoRect.y += this.demoLogoVelocity.y;
    
    
    this.setStatusText(this.graphicsDevice.timer.getFpsString() + " " + this.graphicsDevice.getFaceInfo() + " " + this.loop.stepMillis );
    
}

//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.endDraw = function()
{        
    this.graphicsDevice.endScene(); 
    this.graphicsDevice.present();   
}

//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.toString = function()
{
    return "ajax.xna.Game";
}

//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.loopController = function()
{
    var gameTime = this.graphicsDevice.timer;

    // Time how long this method takes to execute...
    var startTimeMillis = new Date().getMilliseconds();
    
    // method calls...
    
    // Don't do anything until we have something to draw on...(Java takes a while to initialize).
    if (!this.graphicsDevice || !this.graphicsDevice.graphics.hasLoaded || !this.graphicsDevice.graphics.hasLoaded())
        return;
            
    // Update the timer         
    gameTime.iterate();
    
    // Call our update sequence.                
    if (this.graphicsDevice)               
        this.update(gameTime);
    this.updateComponents(gameTime);   
    
    // Draw only if graphics are available
    if (this.graphicsDevice && this.graphicsDevice.graphics.hasLoaded && this.graphicsDevice.graphics.hasLoaded())
    {
        this.beginDraw();            
        this.draw(gameTime); //<-- Clear graphics
        this.drawComponents(gameTime);
        this.endDraw();
    }
    // End timing
    var endTimeMillis             = new Date().getMilliseconds();
    // use targetFramerate/15 here as min value as some browser timers are so innacurate they say it took no time at all
    // or even Negative time to execute this method.
    this.loopMilliseconds   = Math.max(endTimeMillis - startTimeMillis, this.targetFrameRate/15); 

    // If framerate is to be capped, adjust the stepMillis here.
    if (this.targetFrameRate)
        this.loop.stepMillis = Math.max((1000 / this.targetFrameRate) - this.loopMilliseconds, 0);
    
}

//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.onGraphicsCreated = function(e, r)
{///<summary>Make any alterations to the graphics device here (lights etc). No need to call base.</summary>
}

//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.createGraphics = function(deviceType)
{    
    if (this.graphicsDevice != null)          
        this.graphicsDevice.dispose();
        
    this.setBackColour(this.backColour);    
    
    
    // decide what device type to use??    
    deviceType = typeof(deviceType) == "undefined" ? ajax.drawing.DeviceTypes.Canvas : deviceType;       
    
    // Find out what size we want
    var size = this.getContentRect();           
              
    // Create graphicsDevice with scale of 6 (only applies to native rendering).
    this.graphicsDevice = new ajax.drawing.Device3D(this.doc, this.getContent(), "", 
        size.width, size.height, deviceType, 6);   
    
    // Listen out for the on graphics created event of our graphics object.
    this.graphicsDevice.getEvent(this.getWindow(), "onGraphicsCreated").addListener(this.onGraphicsCreated.bind(this));    
    this.graphicsDevice.show(); // Graphics are now loaded and showing (onGraphicsCreated fired off).                    
}

//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.initialize = function()
{///<summary>Call base to create the graphics object</summary>
        
    this.createGraphics();                
}



//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.dispose = function()
{
    // Make sure the loop is no longer running.
    this.loop.stop();
    
    // Call dispose on all our components    
    for (var i = 0; i < this.components.length; i++)
    {
        var gc = ajax.xna.GameComponent.cast(this.components[i]);
        gc.dispose();
        this.components.removeAt(i--);
    }
    
    this.graphicsDevice.dispose();
    this.graphicsDevice = null;    
    
    ajax.xna.Game.superClass.dispose.call(this);
}

//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.run = function()
{///<summary>Starts the game loop for this game. Call this after showing this game form.</summary>
    // Give reasonable first time elapsed time
    this.graphicsDevice.timer.iterate();
    this.loop.start();
}

//-----------------------------------------------------------------------------
ajax.xna.Game.prototype.exit = function()
{///<summary>Stops the game loop and closes this game form. Dispose will later be called.</summary>
    this.loop.stop();
    this.close();
}

//-----------------------------------------------------------------------------
// Overrides
ajax.xna.Game.prototype.load = function()
{
    ajax.xna.Game.superClass.load.call(this); // call base - creates window objects
    
    // Set clipping for Content area, so it will never be tempted to scroll!
    this.getContent().style.clip = String.toFormat("rect(0, {0}px, {1}px, 0)", 
        this.getContentRect().width, this.getContentRect().height
    );
    this.initialize();              // Actually XNA does this components first I think...
    this.initializeComponents();
}

